package xyz.icxl.android.architecture.data.net.repository

import com.safframework.log.L
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
import retrofit2.HttpException
import xyz.icxl.android.architecture.data.ApiResult
import xyz.icxl.android.architecture.data.BRep
import xyz.icxl.android.architecture.exception.RequestApiException
import xyz.icxl.android.architecture.ui.mvvm.BaseViewModel
import java.io.IOException
import java.net.*

open class BaseRepository(private val viewModel: BaseViewModel) {
    suspend fun <T : Any> safeApiCall(
        call: suspend () -> ApiResult<T>,
        errorMessage: String = "request fail."
    ): ApiResult<T> {
        return try {
            call()
        } catch (e: SocketTimeoutException) {
            ApiResult.Error(Exception("connection to server timed out", e))
        } catch (e: ConnectException) {
            ApiResult.Error(
                Exception(
                    "Failed to connect to the server, please check whether the network connection is normal",
                    e
                )
            )
        } catch (e: SocketException) {
            ApiResult.Error(
                Exception(
                    "Failed to connect to the server, please check whether the network connection is normal",
                    e
                )
            )
        } catch (e: UnknownHostException) {
            ApiResult.Error(
                Exception(
                    "Failed to connect to the server, please check whether the network connection is normal",
                    e
                )
            )
        } catch (e: HttpException) {
            //如果需要显示服务器返回的错误信息可以通过 <code>e.response().errorBody().string()</code> 取
            val errorStr = e.response()?.errorBody()?.string()
            if (!errorStr.isNullOrEmpty()) {
                ApiResult.Error(
                    Exception(
                        errorStr
                    )
                )
            } else {
                ApiResult.Error(
                    Exception(
                        "request fail. code is ${
                            e.response()?.errorBody()?.string()
                        }", e
                    )
                )
            }
        } catch (e: Exception) {
            if (e !is NoSuchMethodException) {
                e.printStackTrace()
            }
            L.d("safeApiCall-error->${e.message}")
            ApiResult.Error(IOException(errorMessage, e))
        }
    }

    suspend fun <T : Any> executeResponse(
        response: BRep<T>,
        successBlock: (suspend CoroutineScope.() -> Unit)? = null
    ): ApiResult<T> {
        return coroutineScope {
            if (response.success) {
                successBlock?.let {
                    it()
                }
                ApiResult.Success(response.data)
            } else {
                viewModel.onHttpFail(response)
                ApiResult.Error(RequestApiException(response.code, response.msg))
            }
        }
    }
}